module GYLite {
	export class BatchDrawParam {
		/**样式类型*/public type:BatchDrawType;
		/**X半径*/public radiusX:number;
		/**Y半径*/public radiusY:number;
		/**圆角半径*/public angleRadius:number;
		/**绘制偏移量X*/public offsetX:number;
		/**绘制偏移量Y*/public offsetY:number;
		/**缩放X*/public scaleX:number;
		/**缩放Y*/public scaleY:number;			
		
		public constructor(type:BatchDrawType,radiusX:number=5,radiusY:number=5,scaleX:number=1,scaleY:number=1,offsetX:number=0,offsetY:number=0) 
		{
			let s= this;
			s.type = type;
			s.radiusX = radiusX;
			s.radiusY = radiusY;
			s.offsetX = offsetX;
			s.offsetY = offsetY;
			s.scaleX = scaleX;
			s.scaleY = scaleY;
		}
		/**宽度*/
		public getWidth():number
		{
			let s= this;
			if(s.type == BatchDrawType.CIRCLE)
			{
				return (s.radiusX > 0?s.radiusX*2:s.radiusY*2)*s.scaleX | 0;
			}
			return s.radiusX * 2 * s.scaleX | 0;
		}
		/**高度*/
		public getHeight():number
		{
			let s= this;
			if(s.type == BatchDrawType.CIRCLE)
			{
				return (s.radiusY > 0?s.radiusY*2:s.radiusX*2)*s.scaleY | 0;
			}
			return s.radiusY * 2 * s.scaleY | 0;
		}
		public draw(ctx:CanvasRenderingContext2D, element:HTMLImageElement|HTMLCanvasElement|BatchElement, gap:number=1):void
		{
			BatchDrawParam.draw(ctx,element,this,gap);
		}
		private static drawCircle(ctx:CanvasRenderingContext2D, element:HTMLImageElement|HTMLCanvasElement, param:BatchDrawParam, gap:number=1) {
            
            let size:number,size2:number;
			let offsetX:number,offsetY:number;
			let radiusX:number,radiusY:number;			
			if(param.radiusX > 0)
				radiusY = radiusX = param.radiusX;
			if(param.radiusY > 0)
				radiusY = radiusX = param.radiusY;
			radiusX = radiusX * param.scaleX | 0;
			radiusY = radiusY * param.scaleY | 0;
			offsetX = radiusX + gap + param.offsetX;
			offsetY = radiusY + gap + param.offsetY;
			size = radiusX;		
			size2 = size*2;				
			ctx.save();            
            ctx.clearRect(0, 0, size2 + 2 * gap, size2 + 2 * gap);
            ctx.arc(offsetX, offsetY, size, 0, 2 * Math.PI);
            ctx.clip();			
            ctx.drawImage(element, 0, 0, element.width, element.height, offsetX - radiusX, offsetY - radiusY, size2, size2);
            ctx.restore();
        }
		private static drawRect(ctx:CanvasRenderingContext2D, element:HTMLImageElement|HTMLCanvasElement, param:BatchDrawParam, gap:number=1) {
			let w:number,h:number;
			w = param.getWidth();
			h = param.getHeight();			
            ctx.save();            
            ctx.clearRect(0, 0, w + 2*gap, h + 2*gap);
            ctx.drawImage(element, 0,0,w,h,param.offsetX+gap, param.offsetY+gap, w, h);
            ctx.restore();
        }
		/**圆角绘制(未完成)*/
		private static drawRoundRect(ctx:CanvasRenderingContext2D, element:HTMLImageElement|HTMLCanvasElement, param:BatchDrawParam, gap:number=1):void {
			let w:number,h:number,rw:number,rh:number;
			w = param.getWidth();
			h = param.getHeight();
			rw = param.radiusX * 2;
			rh = param.radiusY * 2;
            ctx.save();            
            ctx.clearRect(0, 0, w + 2*gap, h + 2*gap);
            ctx.drawImage(element, 0,0,w,h,param.offsetX+gap, param.offsetY+gap, w, h);
            ctx.restore();
        }
		/**文本绘制*/
		private static drawText(ctx:CanvasRenderingContext2D, element:GYTextElement, param:BatchDrawParam=null, gap:number=1):void
		{			
			let text:string = element.$char;
			let format:Format = element.$format;			
			let textWidth:number,textHeight:number;
			
			textWidth = element.width;
			textHeight = element.height;			
			              
			ctx.save();
			ctx.textAlign = 'center';
			ctx.textBaseline = 'middle';
			ctx.lineJoin = 'round';
			ctx.font = element.$font;
			// ctx.fillStyle = egret.toColorString(format.textColor);
			ctx.fillStyle = "#ffffff";			
			ctx.clearRect(0, 0, textWidth, textHeight);
			if (format.stroke) {
				ctx.strokeStyle = egret.toColorString(format.strokeColor);
				ctx.lineWidth = element.$stroke2;
				ctx.strokeText(text, textWidth / 2, textHeight / 2);
			}			
			if(format.shadowBlur > 0)
			{
				ctx.shadowBlur=format.shadowBlur;
				ctx.shadowOffsetX=format.shadowOffsetX;
				ctx.shadowOffsetY=format.shadowOffsetY;
				ctx.shadowColor=egret.toColorString(format.shadowColor);
			}			

			ctx.fillText(text, textWidth / 2, textHeight / 2);
			ctx.restore();
		}
		/**矢量绘制*/
		private static graphicsDraw(ctx:CanvasRenderingContext2D, element:GraphicsElement, param:BatchDrawParam, gap:number=1):void
		{
			let width:number,height:number;			
			
			width = element.width;
			height = element.height;
			
			ctx.save();				
			let x:number,y:number,w:number,h:number;			
			ctx.lineJoin = element.lineJoin;
			ctx.lineCap = element.lineCap;
			ctx.fillStyle = element.getFillStyle(ctx);
			ctx.strokeStyle = element.getStrokeStyle(ctx);			
			ctx.clearRect(0, 0, width, height);
			//对1像素和3像素特殊处理，向右下角偏移0.5像素，以显示清晰锐利的线条。			
			// if(element.lineWidth == 1 || element.lineWidth == 3)
				// ctx.translate(0.5,0.5);
			x = element.$originX | 0;//为了保证线条锐利，这里去掉小数
			y = element.$originY | 0;//为了保证线条锐利，这里去掉小数
			w = width - element.$gap2;
			h = height - element.$gap2;
			if(element.$type == GraphicsType.POINT)
			{
				ctx.lineWidth = element.lineWidth;
				BatchDrawParam.drawLineShape(ctx,x,y,x,y);
			}
			else if(element.$type == GraphicsType.LINE)
			{
				ctx.lineWidth = 0;
				if(element.blurSizeY > 0)
				{
					BatchDrawParam.drawLineShape(ctx,x-element.blurSizeX,y-element.blurSizeY,w,h,element.globalAlpha*0.3);
					w -= element.blurSizeX*2;
					h -= element.blurSizeY*2;
				}				
				BatchDrawParam.drawLineShape(ctx,x,y,w,h);
				let imgData:ImageData;
				if(element.$gradientType)
				{
					imgData = ctx.getImageData(1,h>>1,1,1);
					element.startColor = ColorUtil.getRGBColor(imgData.data[0],imgData.data[1],imgData.data[2]);
					imgData = ctx.getImageData(w,h>>1,1,1);
					element.endColor = ColorUtil.getRGBColor(imgData.data[0],imgData.data[1],imgData.data[2]);
				}				
			}
			else if(element.$type == GraphicsType.RECT)
			{
				ctx.lineWidth = 0;
				if(element.blurSizeY > 0)
				{
					BatchDrawParam.drawRectShape(ctx,x-element.blurSizeX,y-element.blurSizeY,w,h,element.globalAlpha*0.3);
					w -= element.blurSizeX*2;
					h -= element.blurSizeY*2;
				}
				BatchDrawParam.drawRectShape(ctx,x,y,w,h);
			}
			else if(element.$type == GraphicsType.ROUNDRECT)
			{
				ctx.lineWidth = 0;
				BatchDrawParam.drawRoundRectShape(ctx,x,y,w,h,element.$rectRadiusX,element.$rectRadiusY);
			}
			else if(element.$type == GraphicsType.CIRCLE || element.$type == GraphicsType.ELLIPSE)
			{
				ctx.lineWidth = 0;				
				w -= element.blurSizeY*2;
				h -= element.blurSizeY*2;
				w /= 2;
				h /= 2;
				BatchDrawParam.drawCircleShape(ctx, x + w, y + h, w, h);
			}			
			ctx.restore();
		}

		/**
		 * 绘制一段圆弧路径
		 * @param x 圆弧中心（圆心）的 x 轴坐标。
		 * @param y 圆弧中心（圆心）的 y 轴坐标。
		 * @param radiusX 圆弧的半径 x。
		 * @param radiusY 圆弧的半径 y。
		 * @param startAngle 圆弧的起始点， x轴方向开始计算，单位以弧度表示。
		 * 注意：必须为正数。
		 * @param endAngle 圆弧的终点， 单位以弧度表示。
		 * 注意：与startAngle差值必须在0~2π之间。
		 * @param anticlockwise 如果为 true，逆时针绘制圆弧，反之，顺时针绘制。
		 * 注意：如果为true，endAngle必须小于startAngle，反之必须大于。
		 */
		private static arcToBezier(ctx:CanvasRenderingContext2D,x:number,y:number,radiusX:number,radiusY:number,startAngle:number,endAngle:number,anticlockwise:boolean=false)
		{
			var halfPI = Math.PI * 0.5;
			var start = startAngle;
			var end = start;
			if (anticlockwise) {
				end += -halfPI - (start % halfPI);
				if (end < endAngle) {
					end = endAngle;
				}
			}
			else {
				end += halfPI - (start % halfPI);
				if (end > endAngle) {
					end = endAngle;
				}
			}
			var currentX = x + Math.cos(start) * radiusX;
			var currentY = y + Math.sin(start) * radiusY;
			ctx.moveTo(currentX, currentY);
			// console.log(currentX,currentY);
			var u = Math.cos(start);
			var v = Math.sin(start);
			for (var i = 0; i < 4; i++) {
				var addAngle = end - start;
				var a = 4 * Math.tan(addAngle / 4) / 3;
				var x1 = currentX - v * a * radiusX;
				var y1 = currentY + u * a * radiusY;
				u = Math.cos(end);
				v = Math.sin(end);
				currentX = x + u * radiusX;
				currentY = y + v * radiusY;
				var x2 = currentX + v * a * radiusX;
				var y2 = currentY - u * a * radiusY;
				ctx.bezierCurveTo(x1, y1, x2, y2, currentX, currentY);						
				// console.log(x1+","+y1+","+x2+","+y2+","+currentX+","+currentY);
				if (end === endAngle) {
					break;
				}
				start = end;
				if (anticlockwise) {
					end = start - halfPI;
					if (end < endAngle) {
						end = endAngle;
					}
				}
				else {
					end = start + halfPI;
					if (end > endAngle) {
						end = endAngle;
					}
				}
			}
		}
		private static drawRoundRectShape(ctx:CanvasRenderingContext2D,x:number,y:number,width:number,height:number,radiusX:number,radiusY):void
		{	
			let hw:number = width * 0.5;
			let hh:number = height * 0.5;
			if (radiusX > hw) {
				radiusX = hw;
			}
			if (radiusY > hh) {
				radiusY = hh;
			}
			if (hw === radiusX && hh === radiusY) {
				if (radiusX === radiusY)
					BatchDrawParam.drawCircleShape(ctx,x + radiusX, y + radiusY, radiusX, radiusY);
				return;
			}				
			//    A-----B
			//  H         C
			//  G         D
			//    F-----E
			// 从D点开始，结束在D点
			var right = x + width;
			var bottom = y + height;
			var xlw = x + radiusX;
			var xrw = right - radiusX;
			var ytw = y + radiusY;
			var ybw = bottom - radiusY;
			ctx.beginPath();
			ctx.moveTo(right, ybw);
			ctx.quadraticCurveTo(right, bottom, xrw, bottom);
			ctx.lineTo(xlw, bottom);
			ctx.quadraticCurveTo(x, bottom, x, ybw);
			ctx.lineTo(x, ytw);
			ctx.quadraticCurveTo(x, y, xlw, y);
			ctx.lineTo(xrw, y);
			ctx.quadraticCurveTo(right, y, right, ytw);
			ctx.lineTo(right, ybw);			
			if(ctx.fillStyle)
				ctx.fill();					
		}
		private static drawRectShape(ctx:CanvasRenderingContext2D,x:number,y:number,width:number,height:number,a:number=1):void
		{			
			if(ctx.fillStyle)
			{	
				ctx.lineWidth = 0;
				// ctx.beginPath();
				// ctx.moveTo(x,y);
				// ctx.lineTo(x + width,y);
				// ctx.lineTo(x + width,y + height);
				// ctx.lineTo(x,y + height);
				// ctx.closePath();
				// ctx.fill();
				ctx.globalAlpha = a;				
				ctx.fillRect(x,y,width,height);
			}
				
		}
		private static drawLineShape(ctx:CanvasRenderingContext2D,x:number,y:number,w:number,h:number,a:number=1):void
		{			
			if(ctx.strokeStyle)
			{				
				ctx.fillStyle = ctx.strokeStyle;
				ctx.globalAlpha = a;				
				ctx.fillRect(x,y,w,h);				
			}	
		}
		private static drawCircleShape(ctx:CanvasRenderingContext2D,x:number,y:number, radiusX:number, radiusY:number) {
			ctx.beginPath();			
			BatchDrawParam.arcToBezier(ctx,x, y, radiusX, radiusY, 0, Math.PI * 2);			
			if(ctx.fillStyle)
				ctx.fill();			
			// if(ctx.strokeStyle)
			// 	ctx.stroke();
		}		

		private static _chineseCharacterMeasureFastMap:any={};
		private static _chineseCharactersRegExp:RegExp = /^[\u4E00-\u9FA5]$/g;
		public static measure(text: string, font:string, format:Format): number {
            const isChinese = BatchDrawParam._chineseCharactersRegExp.test(text);
            if (isChinese) {
                if (BatchDrawParam._chineseCharacterMeasureFastMap[font]) {
                    return BatchDrawParam._chineseCharacterMeasureFastMap[font];
                }
            }
            const measureTextWidth = egret.sys.measureText(text, format.fontFamily, format.size, format.bold, format.italic);
            if (isChinese) {
                BatchDrawParam._chineseCharacterMeasureFastMap[font] = measureTextWidth;
            }
            return measureTextWidth;
        }
		public static draw(ctx:CanvasRenderingContext2D, element:HTMLImageElement|HTMLCanvasElement|BatchElement, param:BatchDrawParam, gap:number=1):void
		{
			if(param.type == BatchDrawType.RECT)
			{
				BatchDrawParam.drawRect(ctx, <HTMLImageElement|HTMLCanvasElement>element, param, gap);
			}
			else if(param.type == BatchDrawType.CIRCLE)
			{
				BatchDrawParam.drawCircle(ctx, <HTMLImageElement|HTMLCanvasElement>element, param, gap);
			}
			else if(param.type == BatchDrawType.ROUND_RECT)
			{
				BatchDrawParam.drawRoundRect(ctx, <HTMLImageElement|HTMLCanvasElement>element, param, gap);
			}
			else if(param.type == BatchDrawType.TEXT)
			{
				BatchDrawParam.drawText(ctx, <GYTextElement>element, param, gap);
			}
			else if(param.type == BatchDrawType.GRAPHICS)
			{
				BatchDrawParam.graphicsDraw(ctx, <GraphicsElement>element, param, gap);
			}
		}
	}
	export class BatchDrawType {
		/**矩形裁切*/public static RECT:BatchDrawType = new BatchDrawType(1,"rect");
		/**圆形裁切*/public static CIRCLE:BatchDrawType = new BatchDrawType(2,"circle");
		/**圆角裁切*/public static ROUND_RECT:BatchDrawType = new BatchDrawType(3,"roundRect");
		/**文本绘制*/public static TEXT:BatchDrawType = new BatchDrawType(4,"text");
		/**graphics绘制*/public static GRAPHICS:BatchDrawType = new BatchDrawType(5,"graphics");
		public $id:number;
		public $name:string;
		constructor(id:number,name:string)
		{
			let s = this;
			s.$id = id;
			s.$name = name;
		}		
	}
}